/**
 * this指向规则：1.函数中的this指向跟函数在哪声明，在哪调用无关。
 *             2.谁调用函数this指向谁，可理解为有点指向点前面的对象，没点严格模式下为undefined,非严格模式下指向window
 *             3.dom事件监听的回调函数里，this指向当前dom
 *             4.构造函数被实例化后，里面的this指向实例对象
 *             5.箭头函数里面不会产生this，它里面的this就是其执行上下文的this
 *             6.可用call、apply、bind改变函数内部this指向
 */

// "use strict"

let obj = {
    fn(){
        console.log(this)

        function innerFn(){
            console.log(this)
        }
        innerFn()

        const arrowFn = ()=>{
            console.log(this)
        }
        arrowFn()
    }
}
obj.fn() // obj  window obj

let fn = obj.fn
fn() // window window window


document.body.addEventListener('click',function(){
    console.log(this) // body
})


document.body.addEventListener('click',()=>{
    console.log(this) // window
})

const newObj = {
    name:'zj'
}
fn.call(newObj, 1, 2) // newObj window newObj
fn.apply(newObj, [1, 2]) // newObj window newObj

const bindFn = fn.bind(newObj,1,2)
bindFn(3, 4) // newObj window newObj

// call的实现
Function.prototype.call = function(context,...params){
    const self = this
    let result 
    context == null ? context = window : null
    typeof context === 'object' ||  typeof context === 'function' ? null : context = Object(context) // context为基本类型
    context[Symbol('key')] = self
    result = context[Symbol('key')](...params)
    delete context[Symbol('key')]
    return result
}

// bind实现
Function.prototype.bind = function(context,...params1){
    const self = this
    return function proxy(...params2){
        self.apply(context,[...params1,...params2])
    }
}
